﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Net.Sockets;
using MyLibrary;

namespace MyLibrary.Net.TCP
{
    public class TCPServerBase<TSession> : HeartBeat where TSession : TCPSession, new()
    {
        private int _port;
        private Socket _socket;
        private List<TSession> _sessions;

        /// <summary>
        /// 会话容量
        /// </summary>
        public int Capacity
        {
            get { return _sessions.Capacity; }
            set
            {
                if (IsRun)
                    throw new TCPException("无法在服务运行中指定会话容量");
                if (value < 1)
                    throw new ArgumentOutOfRangeException();

                _sessions = new List<TSession>(value);
            }
        }

        /// <summary>
        /// 获取所有的会话
        /// </summary>
        public List<TSession> Sessions
        {
            get { return _sessions; }
        }

        /// <summary>
        /// 会话端口
        /// </summary>
        public int Port
        {
            get { return _port; }
            set
            {
                if (IsRun)
                    throw new TCPException("需要在服务器停止时,才能指定服务器的监听端口");
                if (value < 0)
                    throw new ArgumentOutOfRangeException();
                _port = value;
            }
        }

        /// <summary>
        /// 当前服务器的会话数
        /// </summary>
        public int SessionCount
        {
            get { return _sessions.Count; }
        }

        /// <summary>
        /// 服务器使用的套接字
        /// </summary>
        public Socket ServerSocket
        {
            get { return _socket; }
        }

        /// <summary>
        /// 服务器是否已满 
        /// </summary>
        public bool Full
        {
            get{return _sessions.Count >= _sessions.Capacity;}
        }

        /// <summary>
        /// 构造函数
        /// </summary>
        public TCPServerBase() : this(0)
        {

        }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="port">监听的端口</param>
        public TCPServerBase(int port) : this(port,100)
        {
        }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="port">监听的端口</param>
        /// <param name="capacity">会话容量</param>
        public TCPServerBase(int port, int capacity)
        {
            Port = port;
            Capacity = capacity;
        }

        /// <summary>
        /// 报告通讯错误
        /// </summary>
        internal protected virtual void ReportError(TSession session, Exception e)
        {
            if (e is SocketException)
            {
                SocketException se = e as SocketException;
                string msg = String.Format("SocketException Code:{0},Native Code:{1}", se.ErrorCode, se.NativeErrorCode);
                NetDebuger.PrintErrorMessage(session, msg);
            }
            NetDebuger.PrintErrorMessage(session, e.ToString());
        }

        private void SessionReceiveData(object sender, DataBlockArgs e)
        {
            TSession session = (TSession)sender;
            OnReceivedData(session, e.DataBlock);
        }

        private void ReceiveCallback(IAsyncResult parameter)
        {
            TSession session = parameter.AsyncState as TSession;
            try
            {
                if (session.SessionSocket == null)
                    CloseSession(session);
                session._recvResult = null;
                if (session.SessionSocket != null)
                {
                    int readCount = session.SessionSocket.EndReceive(parameter);
                    if (readCount == 0)  //远程已经关闭了
                        CloseSession(session);
                    else
                    {
                        session.ReceivedData(readCount);
                        WaitForData(session); //继续接收数据
                    }
                }
            }
            catch (ObjectDisposedException)
            {
                CloseSession(session);
            }
            catch (NullReferenceException e)
            {
                ReportError(session, e);
                CloseSession(session);
            }
            catch (SocketException e)
            {
                HandleSocketException(session, e);
                CloseSession(session);
            }
            catch (NetException e)
            {
                CloseSession(session);
                ReportError(session, e);
            }
            catch (Exception e)
            {
                //普通异常，不需要断开与服务器的连接
                ReportError(session, e);
            }
        }

        private void SendCallback(IAsyncResult parameter)
        {
            TSession session = (TSession)parameter.AsyncState;
            try
            {
                session._sendResult = null;
                OnSendEnd(session, session.SessionSocket.EndSend(parameter));
            }
            catch (ObjectDisposedException)
            {
                CloseSession(session);
            }
            catch (NullReferenceException)
            {
                CloseSession(session);
            }
            catch (SocketException e)
            {
                HandleSocketException(session, e);

                CloseSession(session);
            }
            catch (Exception e)
            {
                ReportError(session, e);
            }
        }

        private void AcceptCallback(IAsyncResult parameter)
        {
            TSession session = default(TSession);
            try
            {
                //创建新的连接
                session = CreateSession(_socket.EndAccept(parameter));
                if(!Full)
                {
                    lock(Sessions)
                        Sessions.Add(session);
                    //调用客户端生成函数,检查是否为正确的客户端
                    if(!OnCreateSession(session))
                    {
                        session.Close();
                        return;
                    }

                    //注册客户端数据接收事件
                    session.OnReceiveData += new EventHandler<DataBlockArgs>(this.SessionReceiveData);
                    //开始接收客户端数据
                    WaitForData(session);

                    NetDebuger.PrintDebugMessage(session,"Create");
                    NetDebuger.PrintDebugMessage(session,String.Format("Add:{0}/{1}",SessionCount,Capacity));
                }
                else
                {
                    OnServerFull(session);
                    NetDebuger.PrintDebugMessage(session,"Server Full");
                    session.Close();
                }
            }
            catch(SocketException e)
            {
                HandleSocketException(session,e);
                CloseSession(session);
            }
            finally
            {

            }
        }

        protected virtual TSession CreateSession(Socket socket)
        {
            TSession session = new TSession();
            session.SessionSocket = socket;
            if (EnableHB)
                session.TimeCounter.Start();
            return session;
        }

        protected virtual void WaitForData(TSession session)
        {
            DataBlock buffer = session.Buffer;
            if(session.SessionSocket != null)
                session._recvResult = session.SessionSocket.BeginReceive(buffer.Buffer,buffer.WriteIndex,buffer.WriteableLength,
                    SocketFlags.None,new AsyncCallback(ReceiveCallback),session);
        }

        /// <summary>
        /// 发送数据完成
        /// </summary>
        /// <param name="session">发送数据的回话</param>
        /// <param name="sendCount">发送数据个数</param>
        protected virtual void OnSendEnd(TSession session, int sendCount)
        {
        }


        /// <summary>
        /// 关闭会话
        /// </summary>
        /// <param name="session">要关闭的会话</param>
        protected virtual void CloseSession(TSession session)
        {
            lock (Sessions)
            {
                if (Sessions.Contains(session))
                {
                    Sessions.Remove(session);
                    NetDebuger.PrintDebugMessage(session, "Closse");
                    NetDebuger.PrintDebugMessage(session, String.Format("Remove:{0}/{1}", SessionCount, Capacity));
                    OnCloseSession(session);
                    session.Close();
                }
            }
        }

        /// <summary>
        /// 在创建新的会话是调用的方法,继承类可以修改这里的定义.
        /// </summary>
        /// <param name="session">生成的新会话</param>
        protected virtual bool OnCreateSession(TSession session)
        {
            return true;
        }

        /// <summary>
        /// 关闭Session
        /// </summary>
        /// <param name="session">要关闭的Session</param>
        protected virtual void OnCloseSession(TSession session)
        {
        }

        /// <summary>
        /// 接收数据,继承类需要重载该函数,以处理接收到数据后的动作
        /// </summary>
        /// <param name="session">会话</param>
        /// <param name="dataBlock">数据</param>
        protected virtual void OnReceivedData(TSession session, DataBlock dataBlock)
        {
        }

        /// <summary>
        /// 服务器会话已满
        /// </summary>
        protected virtual void OnServerFull(TSession session)
        {
        }

        /// <summary>
        /// 传递Socket错误
        /// </summary>
        protected virtual void HandleSocketException(TSession session,SocketException e)
        {
            //如下事件被认为是Socket关闭时的正常事件
            if(e.ErrorCode != 10054 && e.ErrorCode != 10053 && e.ErrorCode != 10057 && e.ErrorCode != 10058)
                ReportError(session,e);
        }

        public virtual void Send(TSession session, DataBlock data)
        {
            AtomSend(session, data.Buffer, data.ReadIndex, data.DataLength);
        }

        public virtual void Send(TSession session, byte[] data, int startIndex, int length)
        {
            AtomSend(session, data, startIndex, length);
        }

        public void AtomSend(TSession session, byte[] data, int startIndex, int length)
        {
            try
            {
                session._sendResult = session.SessionSocket.BeginSend(data, startIndex, length, SocketFlags.None, new AsyncCallback(SendCallback), session);
            }
            catch (ObjectDisposedException)
            {
                CloseSession(session);
            }
            catch (NullReferenceException)
            {
                CloseSession(session);
            }
            catch (SocketException e)
            {
                HandleSocketException(session, e);
                CloseSession(session);
            }
        }

        protected override void HeartBeatCallback(object o)
        {
            throw new NotImplementedException();
        }

        protected override void Free(bool disposeByUser)
        {
            Stop();
            base.Free(disposeByUser);
        }

        /// <summary>
        /// 启动服务器,开始监听客户端连接
        /// </summary>
        protected override void OnStart()
        {

            base.OnStart();
        }

        protected override void OnStop()
        {
            base.OnStop();  //关闭心跳

            lock (Sessions)
            {
                TSession[] array = Sessions.ToArray();
                foreach (TSession session in array)
                    CloseSession(session);
                Sessions.Clear();
            }

            try
            {
                ServerSocket.Close();
            }
            catch (ObjectDisposedException)
            {
                //服务的套接字已经关闭
            }
            NetDebuger.PrintDebugMessage(this.GetType().Name + " Stop,Clear Resource Success");
        }
    }
}
